﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
using System.Windows.Input;
using System.Xml.Linq;

namespace AnthStat.WPF.Applications
{
    public sealed class FileScreenViewModel : ViewModelBase
    {
        #region Members
        private object _projectsLock = new object();
        private ProjectViewModel _currentProject;
        private ProjectViewModel _newProjectStub;
        private PersonViewModel _mockPersonForCalculator;
        private CsvExporterViewModel _csvExporterViewModel;
        private bool _isShowingNewProject = false;
        private bool _isShowingNewProjectSettings = false;
        private bool _isShowingCalculator = false;
        private bool _isShowingSaveProjectPrompt = false;
        private bool _isShowingCsvExporter = false;
        private bool _isShowingAboutBox = false;
        #endregion Members

        #region Properties

        private ObservableCollection<ProjectTypeViewModel> ProjectTypesCollection { get; set; }

        public ICollectionView ProjectTypesCollectionView { get; private set; }

        public bool IsShowingAboutBox
        {
            get
            {
                return _isShowingAboutBox;
            }
            set
            {
                _isShowingAboutBox = value;
                RaisePropertyChanged("IsShowingAboutBox");
            }
        }

        public CsvExporterViewModel CsvExporterViewModel
        {
            get
            {
                return _csvExporterViewModel;
            }
            set
            {
                _csvExporterViewModel = value;
                RaisePropertyChanged("CsvExporterViewModel");
            }
        }

        public PersonViewModel MockPerson
        {
            get
            {
                return _mockPersonForCalculator;
            }
            set
            {
                _mockPersonForCalculator = value;
                RaisePropertyChanged("MockPerson");
            }
        }

        public bool IsShowingSaveProjectPrompt
        {
            get
            {
                return _isShowingSaveProjectPrompt;
            }
            set
            {
                _isShowingSaveProjectPrompt = value;
                RaisePropertyChanged("IsShowingSaveProjectPrompt");
            }
        }

        public bool IsShowingCsvExporter
        {
            get
            {
                return _isShowingCsvExporter;
            }
            set
            {
                _isShowingCsvExporter = value;
                RaisePropertyChanged("IsShowingCsvExporter");
            }
        }

        public bool IsShowingCalculator
        {
            get
            {
                return _isShowingCalculator;
            }
            set
            {
                _isShowingCalculator = value;
                RaisePropertyChanged("IsShowingCalculator");
            }
        }

        public bool IsShowingNewProject
        {
            get
            {
                return _isShowingNewProject;
            }
            set
            {
                _isShowingNewProject = value;
                RaisePropertyChanged("IsShowingNewProject");
            }
        }

        public bool IsShowingNewProjectSettings
        {
            get
            {
                return _isShowingNewProjectSettings;
            }
            set
            {
                _isShowingNewProjectSettings = value;
                RaisePropertyChanged("IsShowingNewProjectSettings");
            }
        }


        public ProjectViewModel CurrentProject
        {
            get
            {
                return _currentProject;
            }
            private set
            {
                if (_currentProject != value)
                {
                    _currentProject = value;
                    RaisePropertyChanged("CurrentProject");
                }
            }
        }

        public ProjectViewModel NewProjectStub
        {
            get
            {
                return _newProjectStub;
            }
            private set
            {
                _newProjectStub = value;
                RaisePropertyChanged("NewProjectStub");
            }
        }

        public ObservableCollection<ProjectInfoViewModel> Projects { get; private set; }

        #endregion // Properties

        public FileScreenViewModel()
            : base()
        {
            Projects = new ObservableCollection<ProjectInfoViewModel>();
            System.Windows.Data.BindingOperations.EnableCollectionSynchronization(Projects, _projectsLock);
            PopulateCollections();

            AnthStat.Domain.Person person = new Domain.Person(System.Guid.NewGuid().ToString(), DateTime.Now, 1, null)
            {
                Sex = Domain.Sex.Male,
                IsDateBirthEstimated = true
            };

            ProjectTypesCollection = new ObservableCollection<ProjectTypeViewModel>();
            ProjectTypesCollection.Add(new ProjectTypeViewModel("Individual Assessments", "Collect data on children who are repeatedly examined. Useful for tracking and visualizing trends in child growth.", Domain.DataCaptureMode.IndividualAssessments));
            ProjectTypesCollection.Add(new ProjectTypeViewModel("Nutritional Survey", "Collect data based on a sample of children, where each child is measured only once.", Domain.DataCaptureMode.NutritionalSurvey));
            ProjectTypesCollectionView = new CollectionViewSource { Source = ProjectTypesCollection }.View;

            MockPerson = new PersonViewModel(person);
            MockPerson.InitializeCollectionViews();

            MockPerson.AddMeasurementCommand.Execute(null);
        }

        public ICommand ToggleAboutBoxCommand { get { return new RelayCommand(ToggleAboutBoxCommandExecute); } }
        private void ToggleAboutBoxCommandExecute()
        {
            IsShowingAboutBox = !IsShowingAboutBox;
        }

        public ICommand CalculatorCommand { get { return new RelayCommand(CalculatorCommandExecute, CanExecuteCalculatorCommand); } }
        private void CalculatorCommandExecute()
        {
            IsShowingCalculator = !IsShowingCalculator;
        }

        public ICommand PromptCloseProjectCommand { get { return new RelayCommand(PromptCloseProjectCommandExecute, CanExecuteCloseProjectCommand); } }
        private void PromptCloseProjectCommandExecute()
        {
            IsShowingSaveProjectPrompt = true;
        }

        public ICommand ExportToCSVCommand { get { return new RelayCommand(ExportToCSVCommandExecute, CanExecuteCloseProjectCommand); } }
        private void ExportToCSVCommandExecute()
        {
            CsvExporterViewModel = new CsvExporterViewModel(CurrentProject);
            CsvExporterViewModel.IsDisplaying = true;
        }

        public ICommand CloseProjectCommand { get { return new RelayCommand(CloseProjectCommandExecute, CanExecuteCloseProjectCommand); } }
        private void CloseProjectCommandExecute()
        {
            IsShowingSaveProjectPrompt = false;
            CloseCurrentProject();
        }

        public ICommand CloseAndSaveProjectCommand { get { return new RelayCommand(CloseAndSaveProjectCommandExecute, CanExecuteCloseProjectCommand); } }
        private void CloseAndSaveProjectCommandExecute()
        {
            IsShowingSaveProjectPrompt = false;
            CurrentProject.SaveCommand.Execute(null);
            CloseCurrentProject();
        }

        public ICommand CancelCloseProjectCommand { get { return new RelayCommand(CancelCloseProjectCommandExecute, CanExecuteCloseProjectCommand); } }
        private void CancelCloseProjectCommandExecute()
        {
            IsShowingSaveProjectPrompt = false;
        }

        public ICommand CreateProjectCommand { get { return new RelayCommand(CreateProjectCommandExecute, CanExecuteCreateProjectCommand); } }
        private void CreateProjectCommandExecute()
        {
            IsShowingNewProject = true;
            IsShowingNewProjectSettings = false;
        }

        public ICommand CancelNewProjectCommand { get { return new RelayCommand(CancelNewProjectCommandExecute); } }
        private void CancelNewProjectCommandExecute()
        {
            IsShowingNewProject = false;
            IsShowingNewProjectSettings = false;
            _newProjectStub = null;
        }

        public ICommand SelectedProjectTypeCommand { get { return new RelayCommand(SelectedProjectTypeCommandExecute, CanExecuteSelectedProjectTypeCommand); } }
        private void SelectedProjectTypeCommandExecute()
        {
            IsShowingNewProjectSettings = true;

            ProjectTypeViewModel vm = ProjectTypesCollectionView.CurrentItem as ProjectTypeViewModel;

            if(vm != null) 
            {
                if(vm.DataCaptureMode == Domain.DataCaptureMode.IndividualAssessments) 
                {
                    NewProjectStub = new ProjectViewModel("New Individual Assessment", "<add description>", "<add author>", vm.DataCaptureMode);
                }
                else if(vm.DataCaptureMode == Domain.DataCaptureMode.NutritionalSurvey)
                {
                    NewProjectStub = new ProjectViewModel("New Nutritional Survey", "<add description>", "<add author>", vm.DataCaptureMode);
                }
            }
            else 
            {
                throw new InvalidOperationException();
            }
        }

        public ICommand ReturnToProjectTypeSelectorCommand { get { return new RelayCommand(ReturnToProjectTypeSelectorCommandExecute, CanExecuteReturnToProjectTypeSelectorCommand); } }
        private void ReturnToProjectTypeSelectorCommandExecute()
        {
            IsShowingNewProject = true;
            IsShowingNewProjectSettings = false;
            _newProjectStub = null;
        }

        public ICommand CreateNewProjectCommand { get { return new RelayCommand(CreateNewProjectCommandExecute, CanExecuteCreateNewProjectCommand); } }
        private void CreateNewProjectCommandExecute()
        {
            // TODO: Add

            int mode = 0;

            if (NewProjectStub.DataCaptureMode == Domain.DataCaptureMode.NutritionalSurvey) mode = 1;

            XDocument doc = new XDocument(
                new XElement("Project",
                    new XElement("Title", NewProjectStub.Name),
                    new XElement("Author", NewProjectStub.Author),
                    new XElement("Created", DateTime.Now.Ticks.ToString()),
                    new XElement("LastSaved", DateTime.Now.Ticks.ToString()),
                    new XElement("DataCaptureMode", mode.ToString()),
                    new XElement("IndicatorSet", NewProjectStub.IndicatorSet),
                    new XElement("Description", NewProjectStub.Description),
                    new XElement("People")));

            string fileName = NewProjectStub.Name.Replace("?", String.Empty).Replace(":", String.Empty).Replace("/", String.Empty).Replace("\\", String.Empty).Replace("<", String.Empty).Replace(">", String.Empty).Replace("|", String.Empty).Replace("*", String.Empty);
            fileName += ".apj";
            fileName = @"Projects\" + fileName;
            doc.Save(fileName);

            NewProjectStub.SetFileLocation(fileName);

            IsShowingNewProjectSettings = false;
            IsShowingNewProject = false;

            CurrentProject = NewProjectStub;

//            <?xml version="1.0" encoding="utf-8" ?>
//<Project>
//  <Title>Yuritania School System</Title>
//  <Author>Walter Kovacs</Author>
//  <Created>630510000000000000</Created>
//  <LastSaved>631010000000000000</LastSaved>
//  <DataCaptureMode>0</DataCaptureMode>
//  <Description>Individual nutiritional assessments for children registered with the Yuritania School System.</Description>
//  <Version>
//    <Major>1</Major>
//    <Minor>0</Minor>
//    <Release>0</Release>
//    <Build>0</Build>
//  </Version>
        }

        private bool CanExecuteCloseProjectCommand()
        {
            if (CurrentProject == null) return false;
            if (CurrentProject.SaveCommand.CanExecute(null)) return true;
            return false;
        }

        private bool CanExecuteCreateProjectCommand()
        {
            return true;
        }

        private bool CanExecuteCalculatorCommand()
        {
            return true;
        }

        private bool CanExecuteSelectedProjectTypeCommand()
        {
            if (ProjectTypesCollectionView.CurrentItem == null) return false;
            return true;
        }

        private bool CanExecuteReturnToProjectTypeSelectorCommand()
        {
            if (IsShowingNewProjectSettings) return true;
            return false;
        }

        private bool CanExecuteCreateNewProjectCommand()
        {
            if (IsShowingNewProjectSettings && ProjectTypesCollectionView.CurrentItem != null && NewProjectStub != null && !String.IsNullOrEmpty(NewProjectStub.Name)) return true;
            return false;
        }

        public void SetCurrentProject(ProjectInfoViewModel info)
        {
            CurrentProject = new ProjectViewModel(info.Name, info.Description, info.FileInfo.FullName, info.Author, info.IndicatorSet, info.DataCaptureMode);
        }

        public void CloseCurrentProject()
        {
            CurrentProject.Close();
            CurrentProject = null;
        }

        public async void PopulateCollections()
        {
            bool fadeDelay = true;

            if (Directory.Exists(@"Projects"))
            {
                string[] filePaths = Directory.GetFiles(@"Projects", "*.apj", SearchOption.TopDirectoryOnly);

                if (filePaths.Length > 5)
                {
                    fadeDelay = false;
                }

                await Task.Factory.StartNew(delegate
                {
                    lock (_projectsLock)
                    {
                        foreach (string filePath in filePaths)
                        {
                            bool fileFound = false;

                            foreach (ProjectInfoViewModel info in Projects)
                            {
                                FileInfo fi = new FileInfo(filePath);
                                if (info.FileInfo.FullName.Equals(fi.FullName, StringComparison.OrdinalIgnoreCase))
                                {
                                    fileFound = true;
                                    break;
                                }
                            }

                            if (fileFound)
                            {
                                continue;
                            }

                            XDocument doc = new XDocument();

                            try
                            {
                                doc = XDocument.Load(filePath);
                            }
                            catch (Exception)
                            {
                                // invalid XML, skip the project
                                continue;
                            }

                            XElement projectElement = doc.Root;

                            ProjectInfoViewModel projectInfo = new ProjectInfoViewModel()
                            {
                                FileInfo = new FileInfo(filePath),
                                Name = projectElement.Element("Title").Value,
                                Author = projectElement.Element("Author").Value,
                                Description = projectElement.Element("Description").Value,
                                IndicatorSet = projectElement.Element("IndicatorSet").Value,
                                DataCaptureMode = (AnthStat.Domain.DataCaptureMode)(Convert.ToInt32(projectElement.Element("DataCaptureMode").Value))
                            };

                            Projects.Add(projectInfo);

                            if (fadeDelay)
                            {
                                System.Threading.Thread.Sleep(125);
                            }
                        }
                    }
                });
            }
        }
    }
}
